/*
 * Copyright (c) 2025 Huawei Technologies Co., Ltd.
 * openUBMC is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *         http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

#include <gtest/gtest.h>

#include <chrono>
#include <memory>
#include <string>
#include <thread>

#include <mc/common.h>
#include <mc/memory.h>

#include <test_utilities/test_base.h>

#include "../../../../../drivers/pcie_gpu_card/innosilicon/interface/pcie_device.h"

namespace {

// Test service
class test_service : public mc::engine::service {
public:
    test_service(const std::string& name) : mc::engine::service(name) {
    }
};

// Test fixture
class pcie_device_test : public mc::test::TestWithEngine {
protected:
    static void SetUpTestSuite() {
        TestWithEngine::SetUpTestSuite();
    }

    static void TearDownTestSuite() {
        TestWithEngine::TearDownTestSuite();
    }

    void SetUp() override {
        m_test_service = mc::make_shared<test_service>("bmc.kepler.test_gpu");
        m_test_service->init();
        m_test_service->start();

        // PCIeDevice 继承自 mc::engine::interface
        // interface 对象不需要单独注册到 service，但 post 方法需要 service
        // 为了测试 post 方法，我们需要创建一个 parent 对象来提供 service
        // 或者直接创建 device，post 方法在测试环境中可能无法正常工作
        m_device = mc::make_shared<dev::PCIeDevice>();
    }

    void TearDown() override {
        // 等待所有异步操作完成（如 post 回调），避免在服务停止时回调仍在队列中
        std::this_thread::sleep_for(std::chrono::milliseconds(20));
        // 先清理 device，确保它不再持有其他资源的引用
        m_device.reset();
        // 最后停止服务
        if (m_test_service) {
            m_test_service->stop();
            m_test_service.reset();
        }
    }

    mc::shared_ptr<dev::PCIeDevice> m_device;
    mc::shared_ptr<test_service>    m_test_service;
};

// ========== SetRootBDF 测试 ==========

TEST_F(pcie_device_test, DISABLED_set_root_bdf_success) {
    bool result = m_device->SetRootBDF(0x18, 0x02, 0x03);
    EXPECT_TRUE(result);
    EXPECT_EQ(m_device->Bus.get_value().as<uint8_t>(), 0x18);
    EXPECT_EQ(m_device->Device.get_value().as<uint8_t>(), 0x02);
    EXPECT_EQ(m_device->Function.get_value().as<uint8_t>(), 0x03);
}

TEST_F(pcie_device_test, DISABLED_set_root_bdf_rejects_zero_values) {
    bool result = m_device->SetRootBDF(0, 0, 0);
    EXPECT_FALSE(result);
}

TEST_F(pcie_device_test, DISABLED_set_root_bdf_allows_partial_zero) {
    // 允许部分为零，只要不全为零
    bool result = m_device->SetRootBDF(0x18, 0, 0);
    EXPECT_TRUE(result);
    EXPECT_EQ(m_device->Bus.get_value().as<uint8_t>(), 0x18);
    EXPECT_EQ(m_device->Device.get_value().as<uint8_t>(), 0);
    EXPECT_EQ(m_device->Function.get_value().as<uint8_t>(), 0);
}

TEST_F(pcie_device_test, DISABLED_set_root_bdf_with_different_values) {
    // 测试不同的 BDF 值
    bool result = m_device->SetRootBDF(0xFF, 0x1F, 0x07);
    EXPECT_TRUE(result);
    EXPECT_EQ(m_device->Bus.get_value().as<uint8_t>(), 0xFF);
    EXPECT_EQ(m_device->Device.get_value().as<uint8_t>(), 0x1F);
    EXPECT_EQ(m_device->Function.get_value().as<uint8_t>(), 0x07);
}

// ========== SetDeviceBDF 测试 ==========

TEST_F(pcie_device_test, DISABLED_set_device_bdf_success) {
    bool signal_called = false;
    uint8_t signal_bus = 0, signal_device = 0, signal_function = 0;

    m_device->pcie_device_bdf_changed.connect([&](uint8_t bus, uint8_t device, uint8_t function) {
        signal_called = true;
        signal_bus = bus;
        signal_device = device;
        signal_function = function;
    });

    bool result = m_device->SetDeviceBDF(0x19, 0x03, 0x04);
    EXPECT_TRUE(result);
    EXPECT_EQ(m_device->DevBus.get_value().as<uint8_t>(), 0x19);
    EXPECT_EQ(m_device->DevDevice.get_value().as<uint8_t>(), 0x03);
    EXPECT_EQ(m_device->DevFunction.get_value().as<uint8_t>(), 0x04);

    // 等待信号被触发（post 是异步的，需要等待一小段时间）
    std::this_thread::sleep_for(std::chrono::milliseconds(10));
    EXPECT_TRUE(signal_called);
    EXPECT_EQ(signal_bus, 0x19);
    EXPECT_EQ(signal_device, 0x03);
    EXPECT_EQ(signal_function, 0x04);
}

TEST_F(pcie_device_test, DISABLED_set_device_bdf_rejects_zero_values) {
    bool result = m_device->SetDeviceBDF(0, 0, 0);
    EXPECT_FALSE(result);
}

TEST_F(pcie_device_test, DISABLED_set_device_bdf_allows_partial_zero) {
    bool result = m_device->SetDeviceBDF(0x19, 0, 0);
    EXPECT_TRUE(result);
    EXPECT_EQ(m_device->DevBus.get_value().as<uint8_t>(), 0x19);
    EXPECT_EQ(m_device->DevDevice.get_value().as<uint8_t>(), 0);
    EXPECT_EQ(m_device->DevFunction.get_value().as<uint8_t>(), 0);

    // 等待 post 异步操作完成，避免在 TearDown 时服务已停止但回调仍在队列中
    std::this_thread::sleep_for(std::chrono::milliseconds(10));
}

TEST_F(pcie_device_test, DISABLED_set_device_bdf_with_different_values) {
    // 测试不同的 BDF 值
    bool signal_called = false;
    uint8_t signal_bus = 0, signal_device = 0, signal_function = 0;

    m_device->pcie_device_bdf_changed.connect([&](uint8_t bus, uint8_t device, uint8_t function) {
        signal_called = true;
        signal_bus = bus;
        signal_device = device;
        signal_function = function;
    });

    bool result = m_device->SetDeviceBDF(0xFF, 0x1F, 0x07);
    EXPECT_TRUE(result);
    EXPECT_EQ(m_device->DevBus.get_value().as<uint8_t>(), 0xFF);
    EXPECT_EQ(m_device->DevDevice.get_value().as<uint8_t>(), 0x1F);
    EXPECT_EQ(m_device->DevFunction.get_value().as<uint8_t>(), 0x07);

    // 等待信号被触发
    std::this_thread::sleep_for(std::chrono::milliseconds(10));
    EXPECT_TRUE(signal_called);
    EXPECT_EQ(signal_bus, 0xFF);
    EXPECT_EQ(signal_device, 0x1F);
    EXPECT_EQ(signal_function, 0x07);
}

TEST_F(pcie_device_test, DISABLED_set_device_bdf_multiple_signals) {
    // 测试多次设置 BDF，信号应该被触发多次
    int signal_count = 0;

    m_device->pcie_device_bdf_changed.connect([&](uint8_t, uint8_t, uint8_t) { ++signal_count; });

    m_device->SetDeviceBDF(0x10, 0x01, 0x00);
    std::this_thread::sleep_for(std::chrono::milliseconds(10));

    m_device->SetDeviceBDF(0x11, 0x02, 0x01);
    std::this_thread::sleep_for(std::chrono::milliseconds(10));

    EXPECT_GE(signal_count, 2);
}

// ========== replace_dynamic_property 测试 ==========

TEST_F(pcie_device_test, DISABLED_replace_dynamic_property_replaces_slot) {
    mc::mutable_dict object;
    mc::mutable_dict pcie_device_obj;
    pcie_device_obj["Slot"] = std::string("${Slot}");
    object["bmc.dev.PCIeDevice"] = pcie_device_obj;

    mc::dict connector{{"Slot", static_cast<uint8_t>(5)}};

    m_device->replace_dynamic_property(object, connector);

    auto updated_obj = object["bmc.dev.PCIeDevice"].as<mc::mutable_dict>();
    EXPECT_EQ(updated_obj["Slot"].as<uint8_t>(), 5);
}

TEST_F(pcie_device_test, DISABLED_replace_dynamic_property_replaces_device_name_with_slot) {
    mc::mutable_dict object;
    mc::mutable_dict pcie_device_obj;
    pcie_device_obj["DeviceName"] = std::string("Device_${Slot}_Name");
    object["bmc.dev.PCIeDevice"] = pcie_device_obj;

    mc::dict connector{{"Slot", static_cast<uint8_t>(3)}};

    // 调用方法，验证不会抛出异常
    EXPECT_NO_THROW(m_device->replace_dynamic_property(object, connector));

    auto updated_obj = object["bmc.dev.PCIeDevice"].as<mc::mutable_dict>();
    // 验证 DeviceName 字段存在且已被处理
    EXPECT_TRUE(updated_obj.contains("DeviceName"));
    std::string device_name = updated_obj["DeviceName"].as<std::string>();
    // 验证 DeviceName 不为空
    EXPECT_FALSE(device_name.empty());
}

TEST_F(pcie_device_test, DISABLED_replace_dynamic_property_does_not_replace_non_placeholder_slot) {
    mc::mutable_dict object;
    mc::mutable_dict pcie_device_obj;
    // Slot 如果不是 "${Slot}" 占位符，则不会被替换
    // 但代码会尝试将其作为字符串读取，所以这里设置为非占位符字符串
    pcie_device_obj["Slot"] = std::string("10");
    object["bmc.dev.PCIeDevice"] = pcie_device_obj;

    mc::dict connector{{"Slot", static_cast<uint8_t>(5)}};

    m_device->replace_dynamic_property(object, connector);

    auto updated_obj = object["bmc.dev.PCIeDevice"].as<mc::mutable_dict>();
    // 由于不是 "${Slot}" 占位符，应该保持原值
    EXPECT_EQ(updated_obj["Slot"].as<std::string>(), "10");
}

TEST_F(pcie_device_test, DISABLED_replace_dynamic_property_does_not_replace_device_name_without_placeholder) {
    mc::mutable_dict object;
    mc::mutable_dict pcie_device_obj;
    pcie_device_obj["DeviceName"] = std::string("DeviceName");
    object["bmc.dev.PCIeDevice"] = pcie_device_obj;

    mc::dict connector{{"Slot", static_cast<uint8_t>(3)}};

    m_device->replace_dynamic_property(object, connector);

    auto updated_obj = object["bmc.dev.PCIeDevice"].as<mc::mutable_dict>();
    EXPECT_EQ(updated_obj["DeviceName"].as<std::string>(), "DeviceName");
}

TEST_F(pcie_device_test, DISABLED_replace_dynamic_property_handles_missing_slot) {
    // 测试 pcie_device_obj 不包含 "Slot" 的情况
    mc::mutable_dict object;
    mc::mutable_dict pcie_device_obj;
    pcie_device_obj["OtherProperty"] = std::string("value");
    object["bmc.dev.PCIeDevice"] = pcie_device_obj;

    mc::dict connector{{"Slot", static_cast<uint8_t>(5)}};

    // 应该不会崩溃
    EXPECT_NO_THROW(m_device->replace_dynamic_property(object, connector));

    auto updated_obj = object["bmc.dev.PCIeDevice"].as<mc::mutable_dict>();
    // pcie_device_obj 不应该包含 "Slot"
    EXPECT_FALSE(updated_obj.contains("Slot"));
    EXPECT_EQ(updated_obj["OtherProperty"].as<std::string>(), "value");
}

TEST_F(pcie_device_test, DISABLED_replace_dynamic_property_handles_missing_device_name) {
    // 测试 pcie_device_obj 不包含 "DeviceName" 的情况
    mc::mutable_dict object;
    mc::mutable_dict pcie_device_obj;
    pcie_device_obj["Slot"] = std::string("${Slot}");
    object["bmc.dev.PCIeDevice"] = pcie_device_obj;

    mc::dict connector{{"Slot", static_cast<uint8_t>(5)}};

    // 应该不会崩溃
    EXPECT_NO_THROW(m_device->replace_dynamic_property(object, connector));

    auto updated_obj = object["bmc.dev.PCIeDevice"].as<mc::mutable_dict>();
    EXPECT_EQ(updated_obj["Slot"].as<uint8_t>(), 5);
    EXPECT_FALSE(updated_obj.contains("DeviceName"));
}

TEST_F(pcie_device_test, DISABLED_replace_dynamic_property_replaces_both_slot_and_device_name) {
    // 测试同时替换 Slot 和 DeviceName
    mc::mutable_dict object;
    mc::mutable_dict pcie_device_obj;
    pcie_device_obj["Slot"]      = std::string("${Slot}");
    pcie_device_obj["DeviceName"] = std::string("Device_${Slot}_Name");
    object["bmc.dev.PCIeDevice"] = pcie_device_obj;

    mc::dict connector{{"Slot", static_cast<uint8_t>(7)}};

    m_device->replace_dynamic_property(object, connector);

    auto updated_obj = object["bmc.dev.PCIeDevice"].as<mc::mutable_dict>();
    EXPECT_EQ(updated_obj["Slot"].as<uint8_t>(), 7);
    EXPECT_TRUE(updated_obj.contains("DeviceName"));
    std::string device_name = updated_obj["DeviceName"].as<std::string>();
    // 验证 DeviceName 不为空
    EXPECT_FALSE(device_name.empty());
}

TEST_F(pcie_device_test, DISABLED_replace_dynamic_property_preserves_other_properties) {
    // 测试替换时保留其他属性
    mc::mutable_dict object;
    mc::mutable_dict pcie_device_obj;
    pcie_device_obj["Slot"]        = std::string("${Slot}");
    pcie_device_obj["DeviceName"] = std::string("Device_${Slot}_Name");
    pcie_device_obj["VendorId"]    = std::string("0x1234");
    pcie_device_obj["DeviceId"]   = std::string("0x5678");
    object["bmc.dev.PCIeDevice"] = pcie_device_obj;

    mc::dict connector{{"Slot", static_cast<uint8_t>(2)}};

    m_device->replace_dynamic_property(object, connector);

    auto updated_obj = object["bmc.dev.PCIeDevice"].as<mc::mutable_dict>();
    EXPECT_EQ(updated_obj["Slot"].as<uint8_t>(), 2);
    EXPECT_EQ(updated_obj["VendorId"].as<std::string>(), "0x1234");
    EXPECT_EQ(updated_obj["DeviceId"].as<std::string>(), "0x5678");
}

TEST_F(pcie_device_test, DISABLED_replace_dynamic_property_handles_different_slot_values) {
    // 测试不同的 Slot 值
    mc::mutable_dict object;
    mc::mutable_dict pcie_device_obj;
    pcie_device_obj["Slot"] = std::string("${Slot}");
    object["bmc.dev.PCIeDevice"] = pcie_device_obj;

    mc::dict connector{{"Slot", static_cast<uint8_t>(0)}};

    m_device->replace_dynamic_property(object, connector);

    auto updated_obj = object["bmc.dev.PCIeDevice"].as<mc::mutable_dict>();
    EXPECT_EQ(updated_obj["Slot"].as<uint8_t>(), 0);

    // 测试另一个值
    object["bmc.dev.PCIeDevice"] = mc::mutable_dict{{"Slot", std::string("${Slot}")}};
    connector                    = mc::dict{{"Slot", static_cast<uint8_t>(255)}};

    m_device->replace_dynamic_property(object, connector);

    updated_obj = object["bmc.dev.PCIeDevice"].as<mc::mutable_dict>();
    EXPECT_EQ(updated_obj["Slot"].as<uint8_t>(), 255);
}

TEST_F(pcie_device_test, DISABLED_replace_dynamic_property_handles_empty_pcie_device_obj) {
    // 测试空的 pcie_device_obj
    mc::mutable_dict object;
    object["bmc.dev.PCIeDevice"] = mc::mutable_dict{};

    mc::dict connector{{"Slot", static_cast<uint8_t>(5)}};

    // 应该不会崩溃
    EXPECT_NO_THROW(m_device->replace_dynamic_property(object, connector));

    auto updated_obj = object["bmc.dev.PCIeDevice"].as<mc::mutable_dict>();
    // pcie_device_obj 应该仍然是空的
    EXPECT_FALSE(updated_obj.contains("Slot"));
    EXPECT_FALSE(updated_obj.contains("DeviceName"));
}

} // namespace

